﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Path = System.IO.Path;
using Newtonsoft.Json;
using System.Globalization;
using System.Reflection;
using Newtonsoft.Json.Linq;
using TalonUI;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System.Net;
using Talon;

namespace ScriptBox
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
        string currSoftwareVersion;

        TalonsWorkSpace talonsWorkSpace;
        ScriptProject scriptProject;
        TalonsUpdate talonsUpdate;

        string CurrentScriptsPrjPath = "";

        public MainWindow()
        {
            InitializeComponent();

            //加载工作区
            talonsWorkSpace = new TalonsWorkSpace("ScriptboxWS");
            talonsWorkSpace.ReloadMenuEvent += ReloadMenuEventHandlerMethod;
            string tempPath = talonsWorkSpace.Load();
            if (tempPath != null)
            {
                ProjectConfig_Load(tempPath);//打开上一次的项目
            }

            //实例化检查更新
            talonsUpdate = new TalonsUpdate("talonshaw","ScriptBox");
            talonsUpdate.UpdateChecked += TalonsUpdate_UpdateChecked;
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            currSoftwareVersion = assemblyVersion.Substring(0,assemblyVersion.LastIndexOf('.'));
            talonsUpdate.CheckUpdate(currSoftwareVersion);
        }
        private void TalonsUpdate_UpdateChecked(object sender, string newVersion)
        {
            //检查到更新，增加更新菜单
            Dispatcher.Invoke(() =>
            {
                MenuItem updateMenuItem = new MenuItem()
                {
                    Header = "更新",
                    Style = (Style)Resources["UpdateMenuItemStyle"],
                    Margin = new Thickness(10,2,0,2),
                    ToolTip = String.Format("新版本：{0}", newVersion)
                };
                updateMenuItem.Click += Menu_Update_Click;
                Menu_Main.Items.Add(updateMenuItem);
            });
        }

        private void ProjectConfig_Load(string scriptsPrjPath)
        {
            if (!File.Exists(scriptsPrjPath)) return;
            OutputTextBox.Clear();

            CurrentScriptsPrjPath = scriptsPrjPath;
            StackPanel_btnGroup.Children.Clear();

            var json = File.ReadAllText(scriptsPrjPath);

            try
            {
                scriptProject = JsonConvert.DeserializeObject<ScriptProject>(json);
                //计算绝对工作路径
                scriptProject.workDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(scriptsPrjPath), scriptProject.workDir));
            }
            catch (JsonException ex)
            {
                OutputTextBox.Text = $"解析 JSON 文件出错：\n{ex.Message}";
                return;
            }

            this.Title = string.Format("ScriptBox-{0}", scriptProject.projectName);
            talonsWorkSpace.SetCurrentProject(scriptProject.projectName, scriptsPrjPath);

            foreach (ButtonGroup item in scriptProject.buttonGroups)
            {
                if (item.buttons == null) continue;
                WrapPanel wrapPanel = new WrapPanel();
                foreach (ScriptButton scriptButton in item.buttons)
                {
                    ImageSource icon;
                    if (scriptButton.ImgPath == "default" || scriptButton.ImgPath == null)
                    {
                        if (scriptButton.ScriptType == "exe")
                        {
                            string scriptPath = GetAbsoluteScriptPath(scriptButton.ScriptContent);
                            if (File.Exists(scriptPath))
                            {
                                icon = ExeIcon.GetIconImage(scriptPath);
                            }
                            else
                            {
                                icon = new BitmapImage(new Uri("Resources/application.png", UriKind.Relative));
                            }
                        }
                        else if (scriptButton.ScriptType == "bat" || scriptButton.ScriptType == "simpleBat")
                        {
                            icon = new BitmapImage(new Uri("Resources/cmd.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "cmd")
                        {
                            icon = new BitmapImage(new Uri("Resources/cmd.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "file")
                        {
                            icon = new BitmapImage(new Uri("Resources/file.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "dir")
                        {
                            icon = new BitmapImage(new Uri("Resources/folder.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "url")
                        {
                            icon = new BitmapImage(new Uri("Resources/link.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "python")
                        {
                            icon = new BitmapImage(new Uri("Resources/python.png", UriKind.Relative));
                        }
                        else if (scriptButton.ScriptType == "ps1")
                        {
                            icon = new BitmapImage(new Uri("Resources/powershell.png", UriKind.Relative));
                        }
                        else
                        {
                            var imagePath = "Resources/script.png";
                            icon = new BitmapImage(new Uri(imagePath, UriKind.Relative));
                        }
                    }
                    else
                    {
                        var fullImagePath = Path.Combine(Path.GetDirectoryName(scriptsPrjPath), scriptButton.ImgPath);
                        if(File.Exists(fullImagePath))
                        {
                            icon = new BitmapImage(new Uri(fullImagePath));
                        }
                        else
                        {
                            OutputTextBox.Text = $"未找到图标文件：{scriptButton.ImgPath}，将显示默认图标！";
                            var imagePath = "Resources/default.png";
                            icon = new BitmapImage(new Uri(imagePath, UriKind.Relative));
                        }
                    }
                    var iconButton = new IconButton
                    {
                        Title = scriptButton.Title,
                        Icon = icon,
                        Tag = scriptButton,
                        Margin = new Thickness(5),
                        Width = 60
                    };

                    iconButton.Click += Button_Click;
                    wrapPanel.Children.Add(iconButton);
                }
                Label label = new Label();
                label.Foreground = Brushes.Blue;
                label.Content = item.groupName;
                StackPanel_btnGroup.Children.Add(label);
                StackPanel_btnGroup.Children.Add(wrapPanel);
            }
        }

        /// <summary>
        /// 菜单中加载最近项目
        /// </summary>
        /// <returns></returns>
        private void ReloadMenuEventHandlerMethod(object sender, EventArgs e)
        {
            if (talonsWorkSpace.Config.recentProjects.Count() > 0)
            {
                for (int i = Menu_Prj_Recent.Items.Count - 1; i >= 2; i--)
                {
                    Menu_Prj_Recent.Items.RemoveAt(i);
                }

                // 添加最近项目子菜单
                foreach (var project in talonsWorkSpace.Config.recentProjects)
                {
                    MenuItem menuItem = new MenuItem();
                    menuItem.Header = project.name;
                    menuItem.Click += (sender1, e1) =>
                    {
                        // 打开对应的工程文件
                        ProjectConfig_Load(project.path);
                    };
                    Menu_Prj_Recent.Items.Add(menuItem);
                }
            }
        }

        void TextBox_Msg_AddLine(string msg)
        {
            string fullMsg = $"[{DateTime.Now}] {msg}\n";
            // 使用 Dispatcher 来确保在 UI 线程上执行操作
            Dispatcher.Invoke(() =>
            {
                if(msg == null)
                {
                    OutputTextBox.Clear();
                    return;
                }
                
                OutputTextBox.AppendText(fullMsg);
                OutputTextBox.ScrollToEnd();
            });
        }
        string GetAbsoluteScriptPath(string relativePath)
        {
            string scriptPath = "";
            if (Path.IsPathRooted(relativePath))
            {
                scriptPath = relativePath;
                if (!File.Exists(scriptPath))//绝对路径，如果不存在，则不动作
                {
                    return "";
                }
            }
            else
            {
                scriptPath = Path.Combine(Path.GetDirectoryName(scriptProject.workDir), relativePath);//在项目工作路径下找
                if (!File.Exists(scriptPath))//如果脚本文件不存在
                {
                    scriptPath = Path.Combine(Path.GetDirectoryName(CurrentScriptsPrjPath), relativePath);
                    if (!File.Exists(scriptPath))//如果也不存在，则不动作
                    {
                        return "";
                    }
                }
            }
            return scriptPath;
        }
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            bool isWithOutput = false;
            if (!(sender is Button button)) return;
            if (!(button.Tag is ScriptButton scriptButton)) return;

            TextBox_Msg_AddLine(null);

            if (scriptButton.ScriptType == "file" || scriptButton.ScriptType == "dir")//打开文件或文件夹
            {
                string fullPath = "";
                if (Path.IsPathRooted(scriptButton.ScriptContent))
                {
                    fullPath = scriptButton.ScriptContent;
                }
                else
                {
                    fullPath = Path.Combine(scriptProject.workDir, scriptButton.ScriptContent).Replace("/", "\\");
                }
                if (File.Exists(fullPath) || Directory.Exists(fullPath))
                {
                    Process.Start(fullPath);
                    TextBox_Msg_AddLine(scriptButton.Title);
                }
                else
                {
                    TextBox_Msg_AddLine($"{scriptButton.Title}: 未找到项目，请检查路径配置！");
                }
            }
            else if(scriptButton.ScriptType == "url")
            {
                Process.Start(scriptButton.ScriptContent);
                TextBox_Msg_AddLine(scriptButton.Title);
            }
            else
            {
                var startInfo = new ProcessStartInfo
                {
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                if (scriptButton.ScriptType == "cmd")//执行cmd命令
                {
                    startInfo.FileName = "cmd.exe";
                    startInfo.Arguments = $"/c {scriptButton.ScriptContent}";
                    startInfo.WorkingDirectory = scriptProject.workDir;
                    if (scriptButton.ScriptContent.Contains("echo"))
                    {
                        isWithOutput = true;
                    }
                }
                else//运行脚本
                {
                    //以下类型均为脚本文件，检查脚本是否存在
                    string scriptPath = GetAbsoluteScriptPath(scriptButton.ScriptContent);
                    if (scriptPath == "")//如果也不存在，则不动作
                    {
                        TextBox_Msg_AddLine($"{scriptButton.Title}: 未找到脚本文件，请检查路径配置！");
                        return;
                    }
                    switch (scriptButton.ScriptType)
                    {
                        case "simpleBat":
                            startInfo.FileName = scriptPath;
                            startInfo.Arguments = scriptButton.ScriptParameter;
                            startInfo.WorkingDirectory = Path.GetDirectoryName(scriptPath);
                            isWithOutput = true;
                            break;
                        case "bat":
                            startInfo.FileName = scriptPath;
                            startInfo.Arguments = scriptButton.ScriptParameter;
                            startInfo.CreateNoWindow = false;
                            startInfo.RedirectStandardOutput = false;
                            startInfo.RedirectStandardError = false;
                            startInfo.WorkingDirectory = Path.GetDirectoryName(scriptPath);
                            break;
                        case "ps1":
                            startInfo.FileName = "powershell.exe";
                            startInfo.Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{scriptPath} {scriptButton.ScriptParameter}\"";
                            if (scriptPath.Contains(Path.GetDirectoryName(CurrentScriptsPrjPath)))//如果脚本文件在脚本文件夹下
                            {
                                startInfo.WorkingDirectory = scriptProject.workDir;
                            }
                            else
                            {
                                startInfo.WorkingDirectory = Path.GetDirectoryName(scriptPath);
                            }
                            isWithOutput = true;
                            break;
                        case "python":
                            startInfo.FileName = "python.exe";
                            startInfo.Arguments = $"{scriptPath} {scriptButton.ScriptParameter}";
                            if (scriptPath.Contains(Path.GetDirectoryName(CurrentScriptsPrjPath)))//如果脚本文件在脚本文件夹下
                            {
                                startInfo.WorkingDirectory = scriptProject.workDir;
                            }
                            else
                            {
                                startInfo.WorkingDirectory = Path.GetDirectoryName(scriptPath);
                            }
                            isWithOutput = true;
                            break;
                        case "exe":
                            startInfo.FileName = scriptPath;
                            startInfo.Arguments = scriptButton.ScriptParameter;
                            if (scriptButton.ScriptParameter != null)//如果参数不为空，一般参数中为相对路径，则以项目工作路径为工作文件夹
                            {
                                startInfo.WorkingDirectory = scriptProject.workDir;
                                isWithOutput = true;
                            }
                            else if (Path.IsPathRooted(scriptButton.ScriptContent))//如果是绝对路径，说明exe在项目外部（如安装程序），则以项目工作路径为工作文件夹
                            {
                                startInfo.WorkingDirectory = scriptProject.workDir;
                            }
                            else//如果是相对路径，说明exe文件在项目内部，则以exe所在文件夹为工作文件夹
                            {
                                startInfo.WorkingDirectory = Path.GetDirectoryName(scriptPath);
                            }
                            break;
                        default:
                            break;
                    }
                }

                if (isWithOutput == false)
                {
                    var process = new Process { StartInfo = startInfo };
                    process.Start();
                    TextBox_Msg_AddLine(scriptButton.Title);
                }
                else
                {
                    TextBox_Msg_AddLine($"{scriptButton.Title} : 开始执行");
                    var result = await ExecuteScript(startInfo);
                    if (scriptButton.ScriptType != "python")// todo: python脚本未执行完成就会退出进程，故这里不显示其完成信息
                        TextBox_Msg_AddLine($"{scriptButton.Title} : {result}");
                }
            }
            OutputTextBox.ScrollToEnd();
        }
        private void ReplaceLastLine(string newText)
        {
            // 获取TextBox中的文本行
            var lines = OutputTextBox.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();

            // 替换最后一行
            if (lines.Count > 0)
            {
                lines[lines.Count - 1] = newText;
                OutputTextBox.Text = string.Join(Environment.NewLine, lines);
            }
        }
        private async Task<string> ExecuteScript(ProcessStartInfo startInfo)
        {
            if (string.IsNullOrEmpty(startInfo.FileName)) return null;

            var process = new Process { StartInfo = startInfo };

            process.OutputDataReceived += (s, evt) =>// 注意：启动异步输出读取后才会触发接收事件
            {
                if (!string.IsNullOrEmpty(evt.Data))
                {
                    TextBox_Msg_AddLine(evt.Data);
                }
            };

            process.ErrorDataReceived += (s, evt) =>
            {
                if (!string.IsNullOrEmpty(evt.Data))
                {
                    TextBox_Msg_AddLine(evt.Data);
                }
            };

            process.Start();
            process.BeginOutputReadLine(); // 启动异步输出读取
            process.BeginErrorReadLine();

            var processExitedTask = WaitForExitAsync(process);
            await processExitedTask; // 等待进程退出
            return "执行完成";
        }
        // Task extension method to simplify waiting for a process to exit
        private static Task WaitForExitAsync(Process process)
        {
            var tcs = new TaskCompletionSource<bool>();
            process.EnableRaisingEvents = true;
            process.Exited += (sender, args) => tcs.TrySetResult(true);
            if (process.HasExited)
            {
                tcs.TrySetResult(true);
            }
            return tcs.Task;
        }


        private void Menu_Prj_Open_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();

            ofd.Filter = "ScriptBox项目文件|*.sbprj|所有文件|*.*";
            ofd.Title = "选择文件";
            ofd.InitialDirectory = "";

            if (ofd.ShowDialog() == true)
            {
                //此处做你想做的事 ...=ofd.FileName;
                ProjectConfig_Load(ofd.FileName);
            }
        }

        private void Menu_Prj_New_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "项目文件 (*.sbprj)|*.sbprj";
            saveFileDialog.Title = "新建项目";
            saveFileDialog.ShowDialog();

            if (saveFileDialog.FileName == "")
                return;

            // 获取用户选择的文件路径和文件名
            string selectedFilePath = saveFileDialog.FileName;
            string projectDir = Path.GetDirectoryName(selectedFilePath);
            string projectName = Path.GetFileNameWithoutExtension(selectedFilePath);

            // 创建项目文件夹
            string projectFolderPath = Path.Combine(projectDir, "icon");
            Directory.CreateDirectory(projectFolderPath);
            projectFolderPath = Path.Combine(projectDir, "bat");
            Directory.CreateDirectory(projectFolderPath);
            projectFolderPath = Path.Combine(projectDir, "python");
            Directory.CreateDirectory(projectFolderPath);

            // 创建一个匿名类型表示JSON数据
            var data = new
            {
                projectName = projectName,
                workDir = "./",
                buttonGroups = new[]
                {
                    new
                    {
                        groupName = "通用工具",
                        buttons = new[]
                        {
                            new
                            {
                                title = "hello",
                                scriptType = "cmd",
                                scriptContent = "echo Hello World!",
                            }
                        }
                    }
                }
            };

            // 将数据序列化为JSON字符串
            var json = JsonConvert.SerializeObject(data, Formatting.Indented);

            // 将JSON字符串写入文件
            File.WriteAllText(selectedFilePath, json);

            ProjectConfig_Load(selectedFilePath);
        }

        private string GetTextEditorPath()
        {
            // 检查Notepad3安装路径（通过注册表）
            using (var key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
                .OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Notepad3.exe"))
            {
                if (key?.GetValue(null) is string np3Path && File.Exists(np3Path))
                    return np3Path;
            }
        
            // 检查Notepad++安装路径
            using (var key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
                .OpenSubKey(@"SOFTWARE\Notepad++"))
            {
                var npPath = key?.GetValue(null) as string;
                if (!string.IsNullOrEmpty(npPath))
                {
                    var exePath = Path.Combine(npPath, "notepad++.exe");
                    if (File.Exists(exePath))
                        return exePath;
                }
            }
        
            // 使用系统自带记事本
            return Path.Combine(Environment.SystemDirectory, "notepad.exe");
        }

        private void Menu_Prj_Edit_Click(object sender, RoutedEventArgs e)
        {
            var editorPath = GetTextEditorPath();
            Process.Start(editorPath, $"\"{CurrentScriptsPrjPath}\"");
        }

        private void Menu_Prj_Reload_Click(object sender, RoutedEventArgs e)
        {
            ProjectConfig_Load(CurrentScriptsPrjPath);
        }

        private void Menu_About_Click(object sender, RoutedEventArgs e)
        {
            About about = new About(currSoftwareVersion);
            about.Show();
        }
        private void Menu_Update_Click(object sender, RoutedEventArgs e)
        {
            talonsUpdate.StartUpdate();
            Close();
        }

        private void Menu_RecentPrjClear_Click(object sender, RoutedEventArgs e)
        {
            talonsWorkSpace.ClearRecentProject();
        }

        private void Menu_Tool_DbcBalance(object sender, RoutedEventArgs e)
        {
            Window_DbcBalance window_DbcBalance = new Window_DbcBalance();
            window_DbcBalance.Show();
        }
    }

    public class ScriptProject
    {
        public string projectName { get; set; }
        public string workDir { get; set; }
        public List<ButtonGroup> buttonGroups { get; set; }
    }
    public class ButtonGroup
    {
        public string groupName { get; set; }
        public List<ScriptButton> buttons { get; set; }
    }
    public class ScriptButton
    {
        [JsonProperty("title")]
        public string Title { get; set; }

        [JsonProperty("imgPath")]
        public string ImgPath { get; set; }

        [JsonProperty("scriptType")]
        public string ScriptType { get; set; }

        [JsonProperty("scriptContent")]
        public string ScriptContent { get; set; }

        [JsonProperty("scriptParameter")]
        public string ScriptParameter { get; set; }
    }
}

